package org.ragdollcat.first.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.ragdollcat.first.exception.ErrorCode;
import org.ragdollcat.first.exception.ThrowUtils;
import org.ragdollcat.first.model.dto.analyze.*;
import org.ragdollcat.first.model.entity.Picture;
import org.ragdollcat.first.model.entity.Space;
import org.ragdollcat.first.model.entity.User;
import org.ragdollcat.first.model.enums.SpaceTypeEnum;
import org.ragdollcat.first.model.vo.*;
import org.ragdollcat.first.service.AnalyzeService;
import org.ragdollcat.first.service.PictureService;
import org.ragdollcat.first.service.SpaceService;
import org.ragdollcat.first.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class AnalyzeServiceImpl implements AnalyzeService {


    @Resource
    private UserService userService;

    @Resource
    private SpaceService spaceService;

    @Resource
    private PictureService pictureService;

    /**
     * 空间使用情况分析
     *
     * @param request
     * @param httpServletRequest
     * @return
     */
    @Override
    public SpaceUsageAnalyzeResponse spaceUsageAnalyze(SpaceUsageAnalyzeRequest request, HttpServletRequest httpServletRequest) {
        //首先进行权限校验，管理员可以分析共享和私有空间，普通用户只能分析自己的空间
        this.checkAnalyzeAuth(request, userService.getLoginUser(httpServletRequest));
        SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse = new SpaceUsageAnalyzeResponse();
        //公共图库只有已使用大小和当前图片数量
        if (request.isQueryPublic() || request.isQueryAll()) {
            this.publicSpaceUsageAnalyze(request, spaceUsageAnalyzeResponse);
        } else {
            this.privateSpaceUsageAnalyze(request, spaceUsageAnalyzeResponse);
        }
        return spaceUsageAnalyzeResponse;
    }

    /**
     * 空间图片分类分析
     *
     * @param request
     * @param httpServletRequest
     * @return
     */
    @Override
    public List<SpaceCategoryAnalyzeResponse> spaceCategoryAnalyze(SpaceCategoryAnalyzeRequest request, HttpServletRequest httpServletRequest) {
        //首先进行权限校验，管理员可以分析共享和私有空间，普通用户只能分析自己的空间
        this.checkAnalyzeAuth(request, userService.getLoginUser(httpServletRequest));
        //填充参数
        QueryWrapper<Picture> pictureQueryWrapper = new QueryWrapper<>();
        this.fillAnalyzeParam(request, pictureQueryWrapper);
//        select category,count(*),sum(picSize) from picture group by category
        pictureQueryWrapper.select("category as category", "count(*) as count", "sum(picSize) as totalSize").groupBy("category");
        List<Map<String, Object>> maps = pictureService.getBaseMapper().selectMaps(pictureQueryWrapper);
        return maps.stream().map(result -> {
            String category = (String) result.get("category");
            Long count = ((Number) result.get("count")).longValue();
            Long totalSize = ((Number) result.get("totalSize")).longValue();
            return new SpaceCategoryAnalyzeResponse(category, count, totalSize);
        }).collect(Collectors.toList());
    }

    /**
     * 空间标签分类使用分析
     *
     * @param spaceTagAnalyzeRequest
     * @param httpServletRequest
     * @return
     */
    @Override
    public List<SpaceTagAnalyzeResponse> spaceTagAnalyze(SpaceTagAnalyzeRequest spaceTagAnalyzeRequest, HttpServletRequest httpServletRequest) {
        //首先进行权限校验，管理员可以分析共享和私有空间，普通用户只能分析自己的空间
        this.checkAnalyzeAuth(spaceTagAnalyzeRequest, userService.getLoginUser(httpServletRequest));
        //填充参数
        QueryWrapper<Picture> pictureQueryWrapper = new QueryWrapper<>();
        this.fillAnalyzeParam(spaceTagAnalyzeRequest, pictureQueryWrapper);
        pictureQueryWrapper.select("tags").isNotNull("tags");

        List<String> tags = pictureService.getBaseMapper().selectObjs(pictureQueryWrapper).stream().map(Object::toString).collect(Collectors.toList());

        //key tag名称 value 数量
        Map<String, Long> tagsMap = tags.stream().flatMap(tag -> JSONUtil.toList(tag, String.class).stream()).collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));


        return tagsMap.entrySet().stream().sorted(Comparator.comparingLong(Map.Entry::getValue))
                .map(stringLongEntry -> new SpaceTagAnalyzeResponse(stringLongEntry.getKey(), stringLongEntry.getValue())).collect(Collectors.toList());
    }

    /**
     * 空间图片大小分析
     *
     * @param spaceSizeAnalyzeRequest
     * @param httpServletRequest
     * @return
     */
    @Override
    public List<SpaceSizeAnalyzeResponse> spaceSizeAnalyze(SpaceSizeAnalyzeRequest spaceSizeAnalyzeRequest, HttpServletRequest httpServletRequest) {
        //首先进行权限校验，管理员可以分析共享和私有空间，普通用户只能分析自己的空间
        this.checkAnalyzeAuth(spaceSizeAnalyzeRequest, userService.getLoginUser(httpServletRequest));
        //填充参数
        QueryWrapper<Picture> pictureQueryWrapper = new QueryWrapper<>();
        this.fillAnalyzeParam(spaceSizeAnalyzeRequest, pictureQueryWrapper);
        pictureQueryWrapper.select("picSize");
        //得到图片大小
        List<Long> picSizes = pictureService.getBaseMapper().selectObjs(pictureQueryWrapper);

        LinkedList<SpaceSizeAnalyzeResponse> spaceSizeAnalyzeResponses = new LinkedList<>();
        spaceSizeAnalyzeResponses.add(new SpaceSizeAnalyzeResponse("<100 KB", picSizes.stream().filter(picSize -> picSize < 100*1024).count()));
        spaceSizeAnalyzeResponses.add(new SpaceSizeAnalyzeResponse("100 KB-1 MB", picSizes.stream().filter(picSize -> picSize >= 100*1024 && picSize <= 1024*1024).count()));
        spaceSizeAnalyzeResponses.add(new SpaceSizeAnalyzeResponse(">1 MB", picSizes.stream().filter(picSize -> picSize > 1024*1024).count()));
        return spaceSizeAnalyzeResponses;
    }

    /**
     * 用户上传行为分析
     *
     * @param spaceUserAnalyzeRequest
     * @param httpServletRequest
     * @return
     */
    @Override
    public List<SpaceUserAnalyzeResponse> spaceUserAnalyze(SpaceUserAnalyzeRequest spaceUserAnalyzeRequest, HttpServletRequest httpServletRequest) {
        //首先进行权限校验，管理员可以分析共享和私有空间，普通用户只能分析自己的空间
        this.checkAnalyzeAuth(spaceUserAnalyzeRequest, userService.getLoginUser(httpServletRequest));
        //填充参数
        QueryWrapper<Picture> pictureQueryWrapper = new QueryWrapper<>();
        this.fillAnalyzeParam(spaceUserAnalyzeRequest, pictureQueryWrapper);
        Long userId = spaceUserAnalyzeRequest.getUserId();
        //统计每个用户的
        pictureQueryWrapper.eq(ObjUtil.isNotEmpty(userId), "userId", userId);

        //统计维度
        String timeDimension = spaceUserAnalyzeRequest.getTimeDimension();

        switch (timeDimension) {
            case "day":
                pictureQueryWrapper.select("DATE_FORMAT(createTime, '%Y-%m-%d') AS period", "COUNT(*) AS count");
                break;
            case "week":
                pictureQueryWrapper.select("YEARWEEK(createTime) AS period", "COUNT(*) AS count");
                break;
            case "month":
                pictureQueryWrapper.select("DATE_FORMAT(createTime, '%Y-%m') AS period", "COUNT(*) AS count");
                break;
            default:
                ThrowUtils.throwIf(true, ErrorCode.OPERATION_ERROR, "统计维度错误");
        }

        pictureQueryWrapper.groupBy("period").orderByAsc("period");

        //key 时间段 value 上传的图片数量
        List<Map<String, Object>> maps = pictureService.getBaseMapper().selectMaps(pictureQueryWrapper);

        return maps.stream().map(stringObjectMap -> {
            String period = stringObjectMap.get("period").toString();
            Long count = ((Number) stringObjectMap.get("count")).longValue();
            return new SpaceUserAnalyzeResponse(period, count);
        }).collect(Collectors.toList());


    }

    /**
     * 管理员统计占用存储最多的N个空间
     * 只有管理员才能查看
     *
     * @param spaceRankAnalyzeRequest
     * @param httpServletRequest
     * @return
     */
    @Override
    public List<Space> spaceRankAnalyze(SpaceRankAnalyzeRequest spaceRankAnalyzeRequest, HttpServletRequest httpServletRequest) {
        QueryWrapper<Space> spaceQueryWrapper = new QueryWrapper<>();
        spaceQueryWrapper.select("id", "totalSize", "spaceName", "userId").orderByDesc("totalSize").last("LIMIT " + spaceRankAnalyzeRequest.getTopN());
        return spaceService.list(spaceQueryWrapper);
    }

    /**
     * 分析私有图库空间使用情况
     *
     * @param request
     * @param spaceUsageAnalyzeResponse
     * @return
     */
    private void privateSpaceUsageAnalyze(SpaceUsageAnalyzeRequest request, SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse) {
        //私有图库直接根据请求中的spaceId查询空间表
        Long spaceId = request.getSpaceId();
        Space space = spaceService.getById(spaceId);

        Long totalSize = space.getTotalSize();
        Long maxSize = space.getMaxSize();
        spaceUsageAnalyzeResponse.setUsedSize(totalSize);
        spaceUsageAnalyzeResponse.setMaxSize(maxSize);
        spaceUsageAnalyzeResponse.setSizeUsageRatio(NumberUtil.round(((double) (totalSize * 100) / maxSize), 2).doubleValue());
        Long totalCount = space.getTotalCount();
        Long maxCount = space.getMaxCount();
        spaceUsageAnalyzeResponse.setUsedCount(totalCount);
        spaceUsageAnalyzeResponse.setMaxCount(maxCount);
        spaceUsageAnalyzeResponse.setCountUsageRatio(NumberUtil.round(((double) (totalCount * 100) / maxCount), 2).doubleValue());
    }

    /**
     * 分析公共图库或全部图库空间使用情况
     *
     * @param request
     * @param spaceUsageAnalyzeResponse
     */
    private void publicSpaceUsageAnalyze(SpaceUsageAnalyzeRequest request, SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse) {
        QueryWrapper<Picture> pictureQueryWrapper = new QueryWrapper<>();
        fillAnalyzeParam(request, pictureQueryWrapper);
        pictureQueryWrapper.select("picSize");
        List<Long> picSizesList = pictureService.getBaseMapper().selectObjs(pictureQueryWrapper);
        //累加
        long picSizes = picSizesList.stream().mapToLong(value -> (long) value).sum();
        spaceUsageAnalyzeResponse.setUsedSize(picSizes);
        spaceUsageAnalyzeResponse.setUsedCount((long) picSizesList.size());
        spaceUsageAnalyzeResponse.setMaxSize(null);
        spaceUsageAnalyzeResponse.setSizeUsageRatio(null);
        spaceUsageAnalyzeResponse.setMaxCount(null);
        spaceUsageAnalyzeResponse.setCountUsageRatio(null);
    }

    /**
     * 填充查询参数
     *
     * @param spaceAnalyzeRequest
     */
    private void fillAnalyzeParam(SpaceAnalyzeRequest spaceAnalyzeRequest, QueryWrapper<Picture> pictureQueryWrapper) {
        Long spaceId = spaceAnalyzeRequest.getSpaceId();
        boolean queryPublic = spaceAnalyzeRequest.isQueryPublic();
        boolean queryAll = spaceAnalyzeRequest.isQueryAll();


        //查询公共图库，不需要有spaceId
        if (queryPublic) {
            pictureQueryWrapper.isNull("spaceId");
        }
        //查询私有图库,需要有spaceId
        if (!queryPublic && !queryAll) {
            pictureQueryWrapper.eq(ObjUtil.isNotEmpty(spaceId), "spaceId", spaceId);
        }
        //查询所有图库，不需要带spaceId作为查询条件
    }


    /**
     * 权限校验
     *
     * @param request
     * @param user
     */
    private void checkAnalyzeAuth(SpaceAnalyzeRequest request, User user) {
        ThrowUtils.throwIf(ObjUtil.isEmpty(user), ErrorCode.NO_AUTH_ERROR, "请先登录");
        Long spaceId = request.getSpaceId();
        boolean queryPublic = request.isQueryPublic();
        boolean queryAll = request.isQueryAll();
        //校验全空间分析和公共空间分析
        ThrowUtils.throwIf((queryAll || queryPublic) && !userService.isAdmin(user), ErrorCode.NO_AUTH_ERROR, "非管理员无权进行全空间分析！");
        //校验私有空间分析
        Space space = spaceService.getById(spaceId);
        ThrowUtils.throwIf((!queryAll && !queryPublic) && !user.getId().equals(space.getUserId()) && space.getSpaceType().equals(SpaceTypeEnum.PRIVATE.getValue()), ErrorCode.NO_AUTH_ERROR, "您只能对自己的空间进行分析");
    }
}
